package com.gec.controllers;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.gec.entities.Student;
import com.gec.pagination.PagedResult;
import io.quarkus.hibernate.orm.panache.PanacheQuery;
import io.quarkus.panache.common.Page;
import io.quarkus.panache.common.Sort;
import jakarta.annotation.security.RolesAllowed;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import jakarta.transaction.Transactional;
import jakarta.ws.rs.*;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.ext.ExceptionMapper;
import jakarta.ws.rs.ext.Provider;
import org.jboss.logging.Logger;

import java.util.*;

import static com.gec.Generics.GenericHelper.updateEntity;

@Path("student")
@ApplicationScoped
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
@RolesAllowed({"VIEW_ADMIN_DETAILS"})
public class StudentController {
    private static final Logger LOGGER = Logger.getLogger(StudentController.class.getName());

    /**
     * 列出所有学生，支持分页和排序。
     *
     * @param page     页码，从0开始。
     * @param size     每页的记录数。
     * @param sort     排序字段。
     * @param studentName  学生姓名的查询条件。
     * @param gradeLevel   年级的查询条件。
     * @param schoolId     学校ID的查询条件。
     * @return 包含学生列表的响应对象。
     */
    @GET
    public Response listAll(
            @QueryParam("page") Integer page,
            @QueryParam("size") Integer size,
            @QueryParam("sort") String sort,
            @QueryParam("studentName") String studentName,
            @QueryParam("gradeLevel") String gradeLevel,
            @QueryParam("schoolId") Long schoolId
    ) {
        // 初始化分页和排序参数
        size = (size == null) ? 10 : size;
        page = (page == null) ? 0 : page;
        sort = (Objects.equals(sort, "")) ? "studentName" : sort;

        // 确保排序字段有效
        String validSortColumn = "studentName";
        List<String> validSortColumns = Arrays.asList("studentName", "gradeLevel", "schoolId");
        if (validSortColumns.contains(sort)) {
            validSortColumn = sort;
        }

        // 构建基础查询字符串和参数
        String queryStr = "FROM Student WHERE 1=1";
        Map<String, Object> params = new HashMap<>();

        // 根据查询条件构建查询字符串和参数
        if (studentName != null && !studentName.isEmpty()) {
            queryStr += " AND LOWER(studentName) LIKE LOWER(CONCAT('%', :studentName, '%'))";
            params.put("studentName", studentName);
        }
        if (gradeLevel != null && !gradeLevel.isEmpty()) {
            queryStr += " AND LOWER(gradeLevel) LIKE LOWER(CONCAT('%', :gradeLevel, '%'))";
            params.put("gradeLevel", gradeLevel);
        }
        if (schoolId != null) {
            queryStr += " AND school.id = :schoolId";
            params.put("schoolId", schoolId);
        }

        // 创建带有累积参数的查询
        PanacheQuery<Student> query = Student.find(queryStr, Sort.by(validSortColumn), params);

        // 获取总记录数和分页后的学生列表
        Long totalCount = query.count();
        List<Student> students = query.page(Page.of(page, size)).list();

        // 构建并返回分页结果
        return Response.ok(
                new PagedResult<>(
                        students,
                        totalCount,
                        (int) Math.ceil((double) totalCount / size),
                        page > 0,
                        (page + 1) * size < totalCount
                )
        ).build();
    }

    /**
     * 获取单个学生的详细信息。
     *
     * @param id 学生的ID。
     * @return 学生对象，如果找不到则抛出异常。
     */
    @Path("{id}")
    public Student getSingle(Long id) {
        Student entity = Student.findById(id);
        if (entity == null) {
            throw new WebApplicationException("Student with id of " + id + " does not exist.", 404);
        }
        return entity;
    }

    /**
     * 创建新学生。
     *
     * @param entity 新学生对象。
     * @return 包含新创建学生对象的响应。
     */
    @POST
    @Transactional
    public Response create(Student entity) {
        if (entity.id != null) {
            throw new WebApplicationException("Id was invalidly set on request.", 422);
        }

        entity.persist();
        return Response.ok(entity).status(201).build();
    }

    /**
     * 更新学生信息。
     *
     * @param id            学生的ID。
     * @param updatedStudent 更新后的学生对象。
     * @return 包含更新后学生对象的响应。
     */
    @PUT
    @Path("{id}")
    @Transactional
    public Response updateStudent(@PathParam("id") Long id, Student updatedStudent) {
        Student existingStudent = Student.findById(id);
        if (existingStudent == null) {
            throw new WebApplicationException("Student with id " + id + " does not exist.", 404);
        }

        updateEntity(existingStudent, updatedStudent);

        return Response.ok(existingStudent).build();
    }

    /**
     * 删除学生。
     *
     * @param id 学生的ID。
     * @return 表示删除成功的响应。
     */
    @DELETE
    @Path("{id}")
    @Transactional
    public Response delete(Long id) {
        Student entity = Student.findById(id);
        if (entity == null) {
            throw new WebApplicationException("Student with id of " + id + " does not exist.", 404);
        }
        entity.delete();
        return Response.status(204).build();
    }

    /**
     * 全局异常处理映射器，将异常转换为HTTP响应。
     */
    @Provider
    public static class ErrorMapper implements ExceptionMapper<Exception> {

        @Inject
        ObjectMapper objectMapper;

        /**
         * 将异常映射为HTTP响应。
         *
         * @param exception 要处理的异常。
         * @return 包含异常信息的HTTP响应。
         */
        @Override
        public Response toResponse(Exception exception) {
            LOGGER.error("Failed to handle request", exception);

            // 确定HTTP状态码
            int code = 500;
            if (exception instanceof WebApplicationException) {
                code = ((WebApplicationException) exception).getResponse().getStatus();
            }

            // 构建包含异常信息的JSON对象
            ObjectNode exceptionJson = objectMapper.createObjectNode();
            exceptionJson.put("exceptionType", exception.getClass().getName());
            exceptionJson.put("code", code);

            if (exception.getMessage() != null) {
                exceptionJson.put("error", exception.getMessage());
            }

            // 返回包含异常信息的响应
            return Response.status(code)
                    .entity(exceptionJson)
                    .build();
        }

    }
}
